package com.louis.ylog.filter;

import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class BodyCachingHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private static final int MaxContentLength  = 2*1024*1024*8;

    private byte[] body;
    private ServletInputStreamWrapper inputStreamWrapper;

    private Map<String, String> headers= new HashMap<>();

    public BodyCachingHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        headers=getHeaders(request);

        if(request.getContentLength()>MaxContentLength){
            log.info("请求参数长度{}超过日志阈值{}",request.getContentLength(),MaxContentLength);
            return;
        }
        this.body = IOUtils.toByteArray(request.getInputStream());
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.body);
        this.inputStreamWrapper = new ServletInputStreamWrapper(byteArrayInputStream);
        resetInputStream();
    }

    private Map<String,String> getHeaders(HttpServletRequest request){
        Map map = new HashMap();
        Enumeration paramNames = request.getHeaderNames();
        while (paramNames.hasMoreElements()) {
            String headerKey = (String) paramNames.nextElement();
            map.put(headerKey,request.getHeader(headerKey));
        }
        return map;
    }

    private void resetInputStream() {
        this.inputStreamWrapper.setInputStream(new ByteArrayInputStream(this.body != null ? this.body : new byte[0]));
    }

    public String getHeaderStr(){
        return JSON.toJSONString(headers);
    }

    public String getBodyStr() {
        return new String(body);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return this.inputStreamWrapper;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.inputStreamWrapper));
    }


    @Data
    @AllArgsConstructor
    private static class ServletInputStreamWrapper extends ServletInputStream {

        private InputStream inputStream;

        @Override
        public boolean isFinished() {
            return true;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener readListener) {

        }

        @Override
        public int read() throws IOException {
            return this.inputStream.read();
        }
    }
}